import zlib
import math
import re
import shutil
from itertools import chain
from typing import Dict, List, Literal, TypeVar

from utils.JSON的输入和输出 import 读取json
from utils.MiCryptoKey import m_iCryptoKey
from utils.字符utf8长度 import getStringLen
from utils.remove_paragraphs_separator import removeParaSeparator
from utils.创建文件夹 import createFolder

"""
将JSON文件合并 并且加密
"""


def gen_1():
    """
    生成 Name Desc Indx RubyName RubyIndx
    """

    def helper(target_lang: Literal["en", "jp"]):
        name_desc = 读取json("output/5_res/Name&Desc.json")

        CARD_Name_json: list = [item["name"]["zh"] for item in name_desc]
        CARD_Desc_json: list = [item["desc"] for item in name_desc]

        if target_lang == "jp":
            CARD_Desc_json = [removeParaSeparator(s) for s in CARD_Desc_json]

        name_merge_string = "\u0000" * 8  # 开始就有八个空
        desc_merge_string = "\u0000" * 8

        merge_string = {"name": "\u0000" * 8, "desc": "\u0000" * 8}

        name_indx = [0]
        desc_indx = [0]

        for i in range(len(CARD_Name_json)):  # 这里是因为英语的奇怪bug desc比name少一个
            name = CARD_Name_json[i]
            desc = CARD_Desc_json[i]

            def helper(
                sentence: str, indx: List[int], name_or_desc: str, merge_string: dict
            ):

                length = getStringLen(sentence)
                if i == 0:
                    length += 8
                space_len = 4 - length % 4  # 就是拿到余数
                indx.append(indx[-1] + length + space_len)  # 记录indx
                if name_or_desc == "name":
                    merge_string["name"] += sentence + "\u0000" * space_len
                else:
                    merge_string["desc"] += sentence + "\u0000" * space_len

            helper(name, name_indx, "name", merge_string)
            helper(desc, desc_indx, "desc", merge_string)

        # 压缩
        # 不能压缩 压缩反而出问题

        name_indx = [4, 8] + name_indx[1:]
        desc_indx = [4, 8] + desc_indx[1:]

        # print(name_indx)
        # print(desc_indx)

        card_indx = []
        for i in range(len(name_indx)):
            card_indx.append(name_indx[i])
            card_indx.append(desc_indx[i])

        # print(card_indx)

        def intTo4Hex(num: int) -> List[int]:
            res = []
            for _ in range(4):
                res.append(num % 256)
                num //= 256
            return res

        card_indx_merge = []
        for item in card_indx:
            card_indx_merge.extend(intTo4Hex(item))

        # 直接加密
        output_path = f"output/6_res/{target_lang}"
        createFolder(output_path)

        encrypt(
            f"{output_path}/CARD_Name.txt",
            bytes(merge_string["name"], encoding="utf-8"),
        )
        encrypt(
            f"{output_path}/CARD_Desc.txt",
            bytes(merge_string["desc"], encoding="utf-8"),
        )
        encrypt(f"{output_path}/CARD_Indx.txt", bytes(card_indx_merge))

        encrypt(
            f"{output_path}/CARD_RubyName.txt",
            bytes(merge_string["name"], encoding="utf-8"),
        )
        encrypt(f"{output_path}/CARD_RubyIndx.txt", bytes(card_indx_merge))

    helper("en")
    helper("jp")


def gen_2(
    origin_lang: Literal["en", "jp"] = "jp",
):
    """
    根据 pidx 生成 part
    """

    def getPartsOrigin(
        lang: Literal["en", "jp"],
    ) -> List[int]:
        with open(f"output/2_res/{lang}/CARD_Part.txt", "rb") as f:
            hex_str_list = ("{:02X}".format(int(c)) for c in f.read())  # 定义变量接受文件内容
        dec_list = [int(s, 16) for s in hex_str_list]  # 将十六进制转换为十进制
        indx = []
        for i in range(4, len(dec_list), 2):
            indx.append(dec_list[i : i + 2])

        def TwoToOne(x: List[int]) -> int:
            res = 0
            for i in range(1, -1, -1):
                res *= 16 * 16
                res += x[i]
            return res

        return [TwoToOne(i) for i in indx]

    with open(f"output/2_res/{origin_lang}/CARD_Pidx.txt", "rb") as f:
        hex_str_list = ("{:02X}".format(int(c)) for c in f.read())  # 定义变量接受文件内容
    dec_list = [int(s, 16) for s in hex_str_list]  # 将十六进制转换为十进制

    pidx_lengths_divided: List[List[int]] = []  # [[1, 2], [2, 0], ...] 后半部分的拆开
    # 有这样一个关系 pidx_lengths == [sum(x) for x in pidx_lengths_divided]
    pidx_lengths: List[int] = []  # 后半部分 描述分段数
    pidx_offsets: List[int] = []  # 前半部分 描述长度
    for i in range(4, len(dec_list), 4):
        # 计算 pidx_lengths
        tmp = dec_list[i + 3]
        high = math.floor(tmp / 16)
        low = tmp % 16
        pidx_lengths.append(high + low)
        # 计算 pidx_offsets
        pidx_lengths_divided.append([high, low])
        pidx_offsets.append(dec_list[i + 1] * 256 + dec_list[i])

    part_origin = getPartsOrigin(origin_lang)
    parts_of_each_card: List[Dict[str, any]] = []
    # parts_of_each_card 的结构如下
    """
    [
        {
            "slice": [153, 210, 210, 345, 345, 543, 543, 693],
            "parts": [[153, 210], [210, 345], ...],
        }
    ]
    """

    # 生成 parts_of_each_card

    pidx_edited_offsets = [(x - 1) * 2 if x else 0 for x in pidx_offsets]

    for i, start in enumerate(pidx_edited_offsets):
        length = pidx_lengths[i] * 2
        slice = part_origin[start : start + length]
        parts_of_each_card.append({"slice": slice})

    for item in parts_of_each_card:
        slice: List[int] = item["slice"]
        if len(slice):
            parts: List[List[int]] = []
            for i in range(0, len(slice), 2):
                parts.append(slice[i : i + 2])
            item["parts"] = parts
        else:
            item["parts"] = []

    # * 测试 读取日文desc进来裁剪看看

    # desc_list_jp = [x["desc"] for x in 读取json("output/3_res/Name&Desc.json")]

    # for i, desc in enumerate(desc_list_jp):
    #     parts = parts_of_each_card[i]["parts"]
    #     if len(parts):
    #         desc_b = desc.encode("UTF-8")
    #         for start, end in parts:
    #             print(desc_b[start:end].decode("UTF-8"), end="[OVER]\n")

    # 很好 测试OK
    # 接下来读取中文进来 对每一个卡 修改它的parts

    def helper(target_lang: Literal["en", "jp"]):
        desc_list_zh: List[str] = [
            x["desc"] for x in 读取json("output/5_res/Name&Desc.json")
        ]

        if target_lang == "jp":
            desc_list_zh = [removeParaSeparator(s) for s in desc_list_zh]

        for i, desc in enumerate(desc_list_zh):
            starts = [
                m.start() for m in re.finditer("((①|②|③|④|⑤|⑥|⑦)(：))|(【灵摆效果】)", desc)
            ]
            start_end: List[List[int]] = []  # [[0, 101], [101, 200], [200, 300], ...]
            for j in range(len(starts) - 1):
                start_end.append(starts[j : j + 2])
            if len(start_end) > 0:
                start_end.append([start_end[-1][1], len(desc)])  # 加入最后一个
            if len(starts) == 1:
                start_end.append([starts[0], len(desc)])  # 只搜到一个的情况
            start_end = list(
                filter(lambda x: desc[x[0]] != "【", start_end)
            )  # 【灵摆效果】本质上是没用的
            if len(start_end) != pidx_lengths[i]:
                print("切割的产物数和pidx中给出的段数不一致", i, start_end, pidx_lengths[i])
            assert len(start_end) == pidx_lengths[i]
            b_start_end: List[List[int]] = []
            if len(start_end):
                # print(f"[{i}]")
                for item in start_end:
                    while desc[item[-1] - 1] in ["\n", "\r", " "]:  # 切掉末尾的换行什么的
                        item[-1] -= 1
                # for item in start_end:
                #     print(desc[item[0] : item[1]], end="[OVER]\n")
                # 转换成二进制的
                b_start_end = [
                    [len(desc[:start].encode("UTF-8")), len(desc[:end].encode("UTF-8"))]
                    for start, end in start_end
                ]
                # 验证
                # print(b_start_end)
                # desc_b = desc.encode("UTF-8")
                # for start, end in b_start_end:
                #     print(desc_b[start:end].decode("UTF-8"), end="[OVER]\n")

            # 生成新的 parts 和 slice
            parts_of_each_card[i]["parts"] = b_start_end
            parts_of_each_card[i]["slice"] = flatten(b_start_end)

        # 所有的 slice 合并
        slice_merge: List[int] = flatten([part["slice"] for part in parts_of_each_card])

        assert len(slice_merge) == sum(pidx_lengths) * 2

        slice_merge = flatten([[0, 0], slice_merge])  # 补两个在开头
        # slice_merge = flatten([[0, 0], part_origin])  # 测试是不是输出和原版一样

        # 要把 slice_merge 的每一项拆成两项
        slice_merge = flatten([[x % 256, x // 256] for x in slice_merge])

        b_slice_merge = bytes(slice_merge)

        # 尝试输出二进制文件
        # with open("output/test/CARD_Part.txt", "wb") as f:  # 写文件时指定模式为"b"
        #     f.write(b_slice_merge)

        # 最后是加密
        output_path = f"output/6_res/{target_lang}"
        encrypt(f"{output_path}/CARD_Part.txt", b_slice_merge)
        shutil.copy("output/1_res/jp/CARD_Pidx", f"{output_path}/CARD_Pidx.txt")

    helper("en")
    helper("jp")


T = TypeVar("T")


def flatten(l: List[List[T]]) -> List[T]:
    return list(chain.from_iterable(l))


def encrypt(output_name, b: bytes):
    data = bytearray(zlib.compress(b))
    for i in range(len(data)):
        v = i + m_iCryptoKey + 0x23D
        v *= m_iCryptoKey
        v ^= i % 7
        data[i] ^= v & 0xFF
    with open(output_name, "wb") as f:
        f.write((data))
    f.close()


if __name__ == "__main__":
    gen_1()
    gen_2()
    print("success")
